package com.yourenbang.lingyun.transaction.web.service.impl.pay.klks;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
import com.yourenbang.lingyun.constants.AppId;
import com.yourenbang.lingyun.constants.BizCodeMessages;
import com.yourenbang.lingyun.constants.enums.ChannelIdEnums;
import com.yourenbang.lingyun.constants.enums.LetterCodeEnum;
import com.yourenbang.lingyun.constants.enums.PlatNoEnums;
import com.yourenbang.lingyun.constants.enums.table.PayTransactionEnum;
import com.yourenbang.lingyun.core.exception.BizRuntimeException;
import com.yourenbang.lingyun.core.message.Result;
import com.yourenbang.lingyun.core.message.WechatMessageTypeEnum;
import com.yourenbang.lingyun.core.util.BizAssertUtils;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.core.util.date.DateFormat;
import com.yourenbang.lingyun.core.util.date.LocalDateUtils;
import com.yourenbang.lingyun.core.util.redis.CacheKey;
import com.yourenbang.lingyun.core.util.redis.RedisUtils;
import com.yourenbang.lingyun.domain.*;
import com.yourenbang.lingyun.mapper.Merchant20Mapper;
import com.yourenbang.lingyun.mapper.Merchant21Mapper;
import com.yourenbang.lingyun.mapper.UserMerchantRecommend20Mapper;
import com.yourenbang.lingyun.transaction.config.AcmGlobalParams;
import com.yourenbang.lingyun.transaction.config.AcmTransactionParams;
import com.yourenbang.lingyun.transaction.constant.LklTransTypeEnum;
import com.yourenbang.lingyun.transaction.mapper.TransactionMerchantMapper;
import com.yourenbang.lingyun.transaction.mapper.TransactionPayTransactionMapper;
import com.yourenbang.lingyun.transaction.web.domain.dto.migrate.kuaishou.MigrateDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.lakala.LakalaEposFeeDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.lakala.LakalaEposOpenDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.lakala.LakalaEposPayDTO;
import com.yourenbang.lingyun.transaction.web.domain.po.Merchant;
import com.yourenbang.lingyun.transaction.web.service.merchant.MerchantRecommendService;
import com.yourenbang.lingyun.transaction.web.service.pay.PayActivateService;
import com.yourenbang.lingyun.transaction.web.service.pay.PayTransactionOrderService;
import com.yourenbang.lingyun.transaction.web.service.pay.TradeService;
import com.yourenbang.lingyun.transaction.web.service.pay.klks.PayEposService;
import com.yourenbang.lingyun.transaction.web.service.yxy.YxyTradeService;
import com.yourenbang.mcenter.api.model.dto.jpush.PushExtra;
import com.yourenbang.mcenter.api.model.dto.jpush.SendPushDTO;
import com.yourenbang.mcenter.api.model.dto.letter.SendLetterDTO;
import com.yourenbang.mcenter.api.model.dto.msg.WechatMessageDTO;
import com.yourenbang.mcenter.api.service.McenterMessageService;
import com.yourenbang.mcenter.api.service.jpush.JpushApiService;
import com.yourenbang.mcenter.api.service.letter.McenterRpcLetterService;
import com.yourenbang.merchant.api.model.dto.*;
import com.yourenbang.merchant.api.service.klks.MerchantReachApiService;
import com.yourenbang.merchant.api.service.yxy.MerchantYxyApiService;
import com.yourenbang.merchant.api.service.yxy.MerchantYxyReachApiService;
import com.yourenbang.merchant.api.service.yxy.MerchantYxyRewardApiService;
import com.yourenbang.terminal.api.model.dto.*;
import com.yourenbang.terminal.api.service.RpcTerminalService;
import com.yourenbang.terminal.api.service.RpcYxyTerminalService;
import com.yourenbang.transaction.api.model.vo.pay.PayTransaction;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Service("payEposService")
public class PayEposServiceImpl implements PayEposService {

    private static Interner<String> weakInterner = Interners.newWeakInterner();

    @Autowired
    private AcmTransactionParams acmTransactionParams;
    @Autowired
    private AcmGlobalParams acmGlobalParams;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private UserMerchantRecommend20Mapper userMerchantRecommend20Mapper;
    @Autowired
    private TransactionMerchantMapper transactionMerchantMapper;
    @Autowired
    private Merchant20Mapper merchant20Mapper;
    @Autowired
    private Merchant21Mapper merchant21Mapper;
    @Autowired
    private TransactionPayTransactionMapper payTransactionMapper;
    @Autowired
    private PayTransactionOrderService payTransactionOrderService;
    @Autowired
    private RpcTerminalService terminalService;
    @Autowired
    private RpcYxyTerminalService rpcYxyTerminalService;
    @Autowired
    private McenterRpcLetterService mcenterRpcLetterService;
    @Autowired
    private MerchantRecommendService merchantRecommendService;
    @Autowired
    private PayActivateService payActivateService;
    @Autowired
    private MerchantReachApiService merchantReachApiService;
    @Autowired
    private MerchantYxyReachApiService merchantYxyReachApiService;
    @Autowired
    private MerchantYxyRewardApiService merchantYxyRewardApiService;
    @Autowired
    private TradeService tradeService;
    @Autowired
    private JpushApiService jpushApiService;
    @Autowired
    private YxyTradeService yxyTradeService;
    @Autowired
    private McenterMessageService mcenterMessageService;
    @Autowired
    MerchantYxyApiService merchantYxyApiService;

    /**
     * 通知
     */
    @Override
    public void notice(MigrateDTO migrateDTO) {
        if (StringUtils.equals(migrateDTO.getOpt(), MigrateDTO.OPT_TRANSACTION)) {
            payNotice(migrateDTO.getData());
        } else if (StringUtils.equals(migrateDTO.getOpt(), MigrateDTO.OPT_FEE)) {
            feeNotice(migrateDTO.getData());
        } else if (StringUtils.equals(migrateDTO.getOpt(), MigrateDTO.OPT_POS_ACTIVATE)) {
            activate(migrateDTO.getData());
        }
    }

    /**
     * 交易通知
     *
     * @param param 解密后的报文
     */
    private void payNotice(String param) {
        KLog.info("【电签支付通知】入参:{}", param);

        try {
            LakalaEposPayDTO noticeDTO = JSON.parseObject(param, LakalaEposPayDTO.class);

            if (StringUtils.equals(noticeDTO.getTransType(), "012466")) {
                KLog.warn("【电签支付通知】无效的消息,解密后的参数:{}", noticeDTO.toJSON());
                return;
            }

            //系统参考号加锁
            synchronized (weakInterner.intern("payEposNotice" + noticeDTO.getSrefNo())) {
                payNoticeDeal(noticeDTO);
            }

        } catch (BizRuntimeException e) {
            KLog.warn("【电签支付通知】业务异常:{}, 入参:{}", e.getErrorMessage(), param);
        } catch (Exception e) {
            KLog.error("【电签支付通知】异常:{}, 入参:{}", e.getMessage(), param, e);
        }
    }

    /**
     * 电签支付通知处理
     */
    private void payNoticeDeal(LakalaEposPayDTO noticeDTO) {
        Merchant merchant = transactionMerchantMapper.selectByMerchantNo(noticeDTO.getMerchantNo(), PlatNoEnums.YXY.getCode());
        if (merchant == null) {
            KLog.warn("【电签支付通知】未找到商户,解密后的参数:{}", noticeDTO.toJSON());
            //钉钉推送
            String msg = "【电签交易回调】未找到商户\n" +
                    "交易回调参数:" + noticeDTO.toJSON() + "\n" +
                    "请尽快处理";
            KLog.error(msg);
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "未找到商户");
        }
        PayTransactionIndexExample payTransactionIndexExample = new PayTransactionIndexExample();
        payTransactionIndexExample.createCriteria().andOrderNoEqualTo(noticeDTO.getTransactionNo());

        PayTransaction po = new PayTransaction();
        po.setOrderNo(noticeDTO.getTransactionNo());
        po.setTransactionNo(noticeDTO.getTransactionNo());
        po.setUserBaseId(merchant.getUserBaseId());
        po.setMerchantId(merchant.getMerchantId());
        po.setMerchantNo(noticeDTO.getMerchantNo());
        po.setMerchantName(merchant.getMerchantName());
        po.setPhone(merchant.getPhone());
        po.setRealName(merchant.getRealName());
        po.setRate(KlksPayConfig.fmtRate(noticeDTO.getCrdflg(), merchant.getRateCredit()).getShotCode());
        po.setTransactionAmount(new BigDecimal(noticeDTO.getTransAmt()).divide(new BigDecimal("100")));
        po.setTransactionFee(StringUtils.isNotBlank(noticeDTO.getTransFee()) ? new BigDecimal(noticeDTO.getTransFee()) : getFeeByCache(noticeDTO.getTransactionNo()));
        po.setCardFlag(KlksPayConfig.fmtCrdFlg(noticeDTO.getCrdflg()));
        po.setTerminalId(noticeDTO.getTermId());        //终端号
        po.setSn(noticeDTO.getSn());         //机具号
        po.setTransactionCardNo(noticeDTO.getCardNo());
        po.setSettlementCardNo(merchant.getBankCard());
        po.setSettlementBank(merchant.getOpenBank());
        po.setStatus(StringUtils.equals(noticeDTO.getTransStatus(), "S") ? PayTransactionEnum.TransactionStatus.STATUS_10.getCode() : PayTransactionEnum.TransactionStatus.STATUS_20.getCode());
        po.setTransactionTime(DateFormat.DATETIME_COMPACT.parse(noticeDTO.getTransTime()));
        po.setSysRef(noticeDTO.getSrefNo());
        po.setTransType(noticeDTO.getTransType());
        po.setPlatNo(merchant.getPlatNo());
        po.setChannelId(merchant.getChannelId());
        po.setProfitFlag(KlksPayConfig.getProfitFlag(po));
        payTransactionDeal(merchant,po,noticeDTO);
    }

    /**
     * 交易处理
     */
    @Override
    public void payTransactionDeal(Merchant merchant,PayTransaction po,LakalaEposPayDTO noticeDTO) {
        //存在系统参考号,不插入
        PayTransaction oldPay = payTransactionOrderService.getByOrderNo(merchant.getUserBaseId(), noticeDTO.getTransactionNo());
        if (oldPay == null) {
            po.setVersion(0);
            po.setCreateTime(LocalDateTime.now());
            po.setTransactionDay(DateFormat.DATE_COMPACT.format(po.getTransactionTime()));
            po.setTransactionMonth(DateFormat.DATE_MONTH.format(po.getTransactionTime()));
            payTransactionOrderService.insert(po);

            KLog.info("【电签支付通知】插入交易流水:{},解密后的参数:{}", po.toJSON(), noticeDTO.toJSON());
        } else {
            //原状态成功
            if (PayTransactionEnum.TransactionStatus.STATUS_10.isEquals(oldPay.getStatus())) {
                KLog.info("【电签支付通知】原交易已成功,无需处理,解密后的参数:{}", noticeDTO.toJSON());
                return;
            }
            PayTransaction uppo = new PayTransaction();
            BeanUtils.copyProperties(po, uppo);
            uppo.setPayTransactionId(oldPay.getPayTransactionId());
            uppo.setVersion(oldPay.getVersion());
            uppo.setUpdateTime(LocalDateTime.now());
            payTransactionOrderService.updateById(uppo);

            KLog.info("【电签支付通知】更新交易流水:{},解密后的参数:{}", uppo.toJSON(), noticeDTO.toJSON());
        }

        //成功订单处理
        if (PayTransactionEnum.TransactionStatus.STATUS_10.isEquals(po.getStatus())) {

            profitOpt(po);

            if (PlatNoEnums.KLKS.isEquals(po.getPlatNo())) {
                succDeal(po, merchant, noticeDTO);
            } else {
//                succDealYxy(po, merchant);
            }

            //交易极光推送
            sendTransactionLetter(po);

        } else {
            KLog.warn("【电签支付通知】交易未成功,解密后的参数:{}", noticeDTO.toJSON());
        }

    }

    /**
     * 计入分润操作
     */
    @Override
    public void profitOpt(PayTransaction transaction) {
        if (transaction.getProfitFlag()) {

            //发送计分润交易mq
            if (acmTransactionParams.getProfitMqFlag()
                    && !ChannelIdEnums.k40.getCode().equals(transaction.getChannelId())) {
                tradeService.sendProfitPayTransactionMq(transaction);
            }
        }
    }

    @Override
    public void sendTransactionLetter(PayTransaction po) {
        if (StringUtils.equals(po.getTransType(), LklTransTypeEnum.TYPE_412001.getTransType())) {
            return;
        }
        SendLetterDTO letterDTO = new SendLetterDTO();
        Map<String, String> map = new HashMap<>();
        map.put("year", DateFormat.YEAR.format(po.getTransactionTime()));
        map.put("month", DateFormat.MONTH.format(po.getTransactionTime()));
        map.put("date", DateFormat.DAY.format(po.getTransactionTime()));
        map.put("hours", DateFormat.HOURS.format(po.getTransactionTime()));
        map.put("minth", DateFormat.MINUTES.format(po.getTransactionTime()));
        map.put("ss", DateFormat.SECONDS.format(po.getTransactionTime()));
        map.put("amount", String.valueOf(po.getTransactionAmount()));
        letterDTO.setLetterCodeEnum(LetterCodeEnum.NOTICE_TRADE_SUCCESS);
        letterDTO.setPlatNo(po.getPlatNo());
        letterDTO.setUserBaseId(po.getUserBaseId());
        letterDTO.setAppId(PlatNoEnums.KLKS.isEquals(po.getPlatNo()) ? AppId.KLKS_PRO : AppId.YXY_MER);
        letterDTO.setMap(map);
        mcenterRpcLetterService.send(letterDTO);

        //发送小程序通知
        if(PlatNoEnums.YXY.isEquals(po.getPlatNo())){
            String userBaseId=po.getUserBaseId();
            if (ChannelIdEnums.isVirtualChannel(po.getChannelId())) {
                MerchantLinkUser21 merchantLinkUser21 = merchantYxyApiService.getMerchantLinkInfo(userBaseId, po.getChannelId());
                if (Objects.nonNull(merchantLinkUser21)) {
                    userBaseId = merchantLinkUser21.getAppUserBaseId();
                } else {
                    return;
                }
            }
            WechatMessageDTO wechatMessageDTO=new WechatMessageDTO();
            wechatMessageDTO.setUserBaseId(userBaseId);
            wechatMessageDTO.setPath(null);
            wechatMessageDTO.setUrl("https://cdn.static.kaolakuaishou.com/app/yxy/download-merchant.html");
            wechatMessageDTO.setWechatMessageType(WechatMessageTypeEnum.MERCHANT_TRADE_SUCCESS.getCode());
            WechatMessageDTO.MessageStructure first = new WechatMessageDTO.MessageStructure();
            first.setValue("您有一笔交易通知");
            wechatMessageDTO.setFirst(first);
            //交易时间
            WechatMessageDTO.MessageStructure keyword1 = new WechatMessageDTO.MessageStructure();
            keyword1.setValue("一般交易");
            wechatMessageDTO.setKeyword1(keyword1);
            //支付方式
            WechatMessageDTO.MessageStructure keyword2 = new WechatMessageDTO.MessageStructure();
            keyword2.setValue(PayTransactionEnum.CardFlagEnum.getMsgByCode(po.getCardFlag()));
            wechatMessageDTO.setKeyword2(keyword2);
            //交易金额
            WechatMessageDTO.MessageStructure keyword3 = new WechatMessageDTO.MessageStructure();
            keyword3.setValue(po.getTransactionAmount().toPlainString()+"元");
            wechatMessageDTO.setKeyword3(keyword3);
            //交易时间
            WechatMessageDTO.MessageStructure keyword4 = new WechatMessageDTO.MessageStructure();
            keyword4.setValue(LocalDateUtils.formatByDefaultFormat(po.getTransactionTime()));
            wechatMessageDTO.setKeyword4(keyword4);

            WechatMessageDTO.MessageStructure remark = new WechatMessageDTO.MessageStructure();
            remark.setValue("感谢您的使用！");
            wechatMessageDTO.setRemark(remark);
            mcenterMessageService.sendWechatMessage(wechatMessageDTO);
        }
    }


    //成功订单处理
    private void succDeal(PayTransaction trans, Merchant mer, LakalaEposPayDTO noticeDTO) {

        //更新考核开始时间
        updateTerminalActiveTime(mer, trans.getTransactionTime());

        RpcTerminalBindDTO rpcTerminalBindDTO = new RpcTerminalBindDTO();
        rpcTerminalBindDTO.setBindUserBaseId(mer.getUserBaseId());
        rpcTerminalBindDTO.setTerminalSn(noticeDTO.getSn());
        Terminal epos = terminalService.getBind(rpcTerminalBindDTO).getData();
        if (Objects.isNull(epos)) {
            KLog.warn("【电签支付通知】未找到机具信息,解密后的参数:{},", noticeDTO.toJSON());
            return;
        }

        //更新商户优惠费率时间
        updateDiscountsRate(mer, epos);

        //更新电签商户标识
        merchantRecommendService.updateEposMerFlag(mer.getUserBaseId(), mer.getChannelId());

        //激活返现
        bounty(trans, mer, epos, noticeDTO);

    }

    /**
     * 更新商户考核开始时间
     */
    private void updateTerminalActiveTime(Merchant mer, LocalDateTime assessBeginTime) {
        //更新考核开始时间
        if (mer.getTerminalActiveTime() == null) {
            if (PlatNoEnums.YXY.isEquals(mer.getPlatNo())) {
                Merchant21 upMer = new Merchant21();

                upMer.setMerchantId(mer.getMerchantId());
                if (assessBeginTime == null) {
                    upMer.setTerminalActiveTime(LocalDateTime.now());
                } else {
                    upMer.setTerminalActiveTime(assessBeginTime);
                }
                upMer.setUpdateTime(LocalDateTime.now());
                int updateCount = merchant21Mapper.updateByPrimaryKeySelective(upMer);
                BizAssertUtils.assertOne(updateCount, "更新通道商户失败");

                mer.setTerminalActiveTime(upMer.getTerminalActiveTime());
            } else {
                Merchant20 upMer = new Merchant20();

                upMer.setMerchantId(mer.getMerchantId());
                if (assessBeginTime == null) {
                    upMer.setTerminalActiveTime(LocalDateTime.now());
                } else {
                    upMer.setTerminalActiveTime(assessBeginTime);
                }
                upMer.setUpdateTime(LocalDateTime.now());
                int updateCount = merchant20Mapper.updateByPrimaryKeySelective(upMer);
                BizAssertUtils.assertOne(updateCount, "更新通道商户失败");

                mer.setTerminalActiveTime(upMer.getTerminalActiveTime());
            }
        }
    }

    /**
     * 更新商户优惠费率时间-银小云&快收
     */
    private void updateDiscountsRate(Merchant mer, Terminal epos) {
        if (mer.getDiscountsRateBeginTime() != null) {
            return;
        }
        if (epos.getTerminalRateId() == null) {
            KLog.warn("【更新商户优惠费率时间】机具费率id空, epos:{}", epos.toString());
            return;
        }

        if (PlatNoEnums.YXY.isEquals(mer.getPlatNo())){
            RpcYxyTerminalRateDTO rpcTerminalRateDTO = new RpcYxyTerminalRateDTO();
            rpcTerminalRateDTO.setTerminalRateId(epos.getTerminalRateId());
            TerminalRate eposRate = rpcYxyTerminalService.getRate(rpcTerminalRateDTO).getData();
            if (eposRate == null) {
                KLog.warn("【更新商户优惠费率时间】未获取到机具费率策略, epos:{}", epos.toString());
                return;
            }
            Merchant21 upMer = new Merchant21();
            upMer.setMerchantId(mer.getMerchantId());
            upMer.setDiscountsRateBeginTime(LocalDateUtils.localDateToLocalDateTime(mer.getTerminalActiveTime().toLocalDate()));
            upMer.setDiscountsRateEndTime(LocalDateUtils.localDateToLocalDateTime(mer.getTerminalActiveTime().plusDays(eposRate.getTerminalRateDiscountDay()).toLocalDate()));
            upMer.setDiscountsRatePastFlag("0");
            int updateCount = merchant21Mapper.updateByPrimaryKeySelective(upMer);
            BizAssertUtils.assertOne(updateCount, "更新通道商户失败");
        } else if (PlatNoEnums.KLKS.isEquals(mer.getPlatNo())){
            RpcTerminalRateDTO rpcTerminalRateDTO = new RpcTerminalRateDTO();
            rpcTerminalRateDTO.setTerminalRateId(epos.getTerminalRateId());
            TerminalRate eposRate = terminalService.getRate(rpcTerminalRateDTO).getData();
            if (eposRate == null) {
                KLog.warn("【更新商户优惠费率时间】未获取到机具费率策略, epos:{}", epos.toString());
                return;
            }
            Merchant20 upMer = new Merchant20();
            upMer.setMerchantId(mer.getMerchantId());
            upMer.setDiscountsRateBeginTime(LocalDateUtils.localDateToLocalDateTime(mer.getTerminalActiveTime().toLocalDate()));
            upMer.setDiscountsRateEndTime(LocalDateUtils.localDateToLocalDateTime(mer.getTerminalActiveTime().plusDays(eposRate.getTerminalRateDiscountDay()).toLocalDate()));
            upMer.setDiscountsRatePastFlag("0");
            int updateCount = merchant20Mapper.updateByPrimaryKeySelective(upMer);
            BizAssertUtils.assertOne(updateCount, "更新通道商户失败");
        }
    }

    private void bounty(PayTransaction trans, Merchant mer, Terminal epos, LakalaEposPayDTO noticeDTO) {

        //未返现 且 激活当日的交易
        if (mer.getBountyFlag() != 0) {
            return;
        }

        if (mer.getTerminalActiveTime() == null) {
            KLog.info("【电签支付通知】激活返现, 考核开始时间空,不返现,解密后的参数:{}", noticeDTO.toJSON());
            return;
        }

        //非激活当天交易
        if (!StringUtils.equals(DateFormat.DATE_COMPACT.format(mer.getTerminalActiveTime()), DateFormat.DATE_COMPACT.format(trans.getTransactionTime()))) {
            KLog.info("【电签支付通知】激活返现, 非当天交易,不返现,解密后的参数:{}", noticeDTO.toJSON());
            return;
        }

        BigDecimal his = payTransactionMapper.sumEposByUserId(KlksPayConfig.getTransTableIndex(trans.getUserBaseId()), trans.getUserBaseId(), DateFormat.DATE_COMPACT.format(mer.getTerminalActiveTime()));
        if (his.compareTo(new BigDecimal("100")) < 0) {
            KLog.info("【电签支付通知】激活返现, 交易总额:{}, 未达到100元不返现,解密后的参数:{}", his, noticeDTO.toJSON());
            return;
        }

        //第一阶段达标
        if (ChannelIdEnums.epos_p30.isEquals(epos.getChannelId())) {
            FirstReachP30DTO firstReachP30DTO = new FirstReachP30DTO();
            firstReachP30DTO.setUserBaseId(mer.getUserBaseId());
            firstReachP30DTO.setReachAmt(his);
            merchantReachApiService.firstReachP30(firstReachP30DTO);
        } else {
            FirstReachP20DTO firstReachP20DTO = new FirstReachP20DTO();
            firstReachP20DTO.setUserBaseId(mer.getUserBaseId());
            firstReachP20DTO.setReachAmt(his);
            merchantReachApiService.firstReachP20(firstReachP20DTO);
        }


        if (mer.getChannelId().equals(epos.getChannelId())) {
            //激活返现
            payActivateService.eposMerBounty(mer, epos);
        } else {
            KLog.info("【电签支付通知】激活返现, 通道商户类型:{}, 机具类型:{},不一致,解密后的参数:{}", mer.getChannelId(), epos.getChannelId(), noticeDTO.toJSON());
            Merchant20 upMer = new Merchant20();
            LocalDateTime now = LocalDateTime.now();
            upMer.setMerchantId(mer.getMerchantId());
            upMer.setRemarks(mer.getRemarks() + ";商户类型与机具类型不一致,不返现," + now);
            upMer.setUpdateTime(now);
            int updateCount = merchant20Mapper.updateByPrimaryKeySelective(upMer);
            BizAssertUtils.assertOne(updateCount, "更新通道商户失败");
        }
    }

    //从缓存中尝试获取手续费
    private BigDecimal getFeeByCache(String transactionNo) {
        BigDecimal fee = redisUtils.get(getFeeNoticeCacheKey(transactionNo), BigDecimal.class);
        if (fee == null) {
            return BigDecimal.ZERO;
        }
        return fee;
    }

    private CacheKey getFeeNoticeCacheKey(String transactionNo) {
        return new CacheKey(CacheKey.CacheKeyPrefix2.pay,
                StringUtils.join(new String[]{"payEposFeeNotice", transactionNo}, ":"));
    }

    /**
     * 手续费通知
     *
     * @param param 解密后的报文
     */
    private void feeNotice(String param) {
        KLog.info("【电签手续费通知】入参:{}", param);
        LakalaEposFeeDTO feeDTO = JSON.parseObject(param, LakalaEposFeeDTO.class);

        PayTransaction oldPay = payTransactionOrderService.getByOrderNo(feeDTO.getTransactionNo());

        if (oldPay == null) {
            KLog.warn("【电签手续费通知】未找到交易,缓存费率信息,解密后的参数:{}", param);
            redisUtils.set(getFeeNoticeCacheKey(feeDTO.getTransactionNo()), feeDTO.getTransFee(), 60 * 30);
            return;
        }
        if (oldPay.getTransactionFee() != null
                && oldPay.getTransactionFee().compareTo(BigDecimal.ZERO) != 0) {
            KLog.info("【电签手续费通知】已更新手续费信息,解密后的参数:{}", param);
            return;
        }

        PayTransaction upPay = new PayTransaction();
        upPay.setPayTransactionId(oldPay.getPayTransactionId());
        upPay.setVersion(oldPay.getVersion());
        upPay.setUserBaseId(oldPay.getUserBaseId());
        upPay.setUpdateTime(LocalDateTime.now());
        upPay.setOrderNo(feeDTO.getTransactionNo());
        upPay.setTransactionNo(feeDTO.getTransactionNo());
        upPay.setTransactionFee(new BigDecimal(feeDTO.getTransFee()));
        payTransactionOrderService.updateById(upPay);

    }

    /**
     * 电签机具激活通知-银小云
     */
    private void activate(String param) {
        KLog.info("【电签机具激活通知】入参:{}", param);
        LakalaEposOpenDTO posDTO = JSON.parseObject(param, LakalaEposOpenDTO.class);

        if (!StringUtils.equals(posDTO.getRetCode(), LakalaEposOpenDTO.STATUS_SUCC)) {
            KLog.warn("【电签机具激活通知】拉卡拉返回未成功,解密后的参数:{}", posDTO.toJSON());
            return;
        }

        Merchant payMer = transactionMerchantMapper.selectByMerchantNo(posDTO.getMerchantNo(), PlatNoEnums.YXY.getCode());
        if (payMer == null) {
            KLog.warn("【电签机具激活通知】未找到通道商户信息,解密后的参数:{}", posDTO.toJSON());
            return;
        }

        if (StringUtils.equals(posDTO.getTxnCode(), LakalaEposOpenDTO.TXNCODE_OPEN)) {
            KLog.info("【电签机具激活通知】交易码为激活类型,解密后的参数:{}", posDTO.toJSON());
            posOpen(posDTO, payMer);
        } else if (StringUtils.equals(posDTO.getTxnCode(), LakalaEposOpenDTO.TXNCODE_REVERSE_OPEN)) {
            KLog.info("【电签机具激活通知】交易码为强制反激活类型,解密后的参数:{}", posDTO.toJSON());
            posReverseOpen(payMer);
        }
    }

    /**
     * 机具激活-银小云
     */
    private void posOpen(LakalaEposOpenDTO posDTO, Merchant payMer) {

        RpcYxyCallbackBindDTO toBindDTO = new RpcYxyCallbackBindDTO();

        toBindDTO.setSn(posDTO.getTerminalSeq());
        toBindDTO.setUserBaseId(payMer.getUserBaseId());
        toBindDTO.setAuthCode(posDTO.getAuthCode());
        toBindDTO.setChannelId(payMer.getChannelId());
        toBindDTO.setMerchantNo(payMer.getMerchantNo());
        Result<Terminal> bindResult = rpcYxyTerminalService.callbackBind(toBindDTO);

        if (!bindResult.isSuccess()) {
            KLog.warn("【机具激活】绑定机具失败:{},posDTO:{}", bindResult.getDesc(), posDTO.toJSON());
            return;
        }
        Terminal terminal = bindResult.getData();

        //更新考核开始时间
        updateTerminalActiveTime(payMer, StringUtils.isNotBlank(posDTO.getLogDate()) ? DateFormat.DATETIME_COMPACT.parse(posDTO.getLogDate() + "000001") : null);
        //更新商户优惠费率时间
        updateDiscountsRate(payMer, terminal);
        //激活机具推送
        merOpenJpush(payMer.getUserBaseId(), payMer.getPlatNo());
        //更新电签商户标识
        if (PlatNoEnums.YXY.isEquals(payMer.getPlatNo())) {
            merchantRecommendService.updateEposMerFlagYxy(payMer.getUserBaseId(), terminal.getChannelId());
        }else {
            merchantRecommendService.updateEposMerFlag(payMer.getUserBaseId(), terminal.getChannelId());
        }

        //调用达标
        if (ChannelIdEnums.epos.isEquals(terminal.getChannelId())) {
            CreateP20ReachDTO reachDTO = new CreateP20ReachDTO();
            reachDTO.setUserBaseId(payMer.getUserBaseId());
            merchantReachApiService.createP20Reach(reachDTO);
        } else if (ChannelIdEnums.epos_p30.isEquals(terminal.getChannelId())) {
            CreateP30ReachDTO reachDTO = new CreateP30ReachDTO();
            reachDTO.setUserBaseId(payMer.getUserBaseId());
            merchantReachApiService.createP30Reach(reachDTO);
        }else if (ChannelIdEnums.yxy_lkl_p42.isEquals(terminal.getChannelId())) {
            CreateYxyReachDTO createYxyReachDTO = new CreateYxyReachDTO();
            createYxyReachDTO.setUserBaseId(payMer.getUserBaseId());
            createYxyReachDTO.setPlatNo(PlatNoEnums.YXY.getCode());
            createYxyReachDTO.setActiveTime(payMer.getTerminalActiveTime() == null
                    ? LocalDateTime.now() : payMer.getTerminalActiveTime());
            createYxyReachDTO.setChannelId(terminal.getChannelId());

            merchantYxyReachApiService.createYxyReach(createYxyReachDTO);

            CreateRewardYxyDTO createRewardYxyDTO = new CreateRewardYxyDTO();
            createRewardYxyDTO.setFromUserBaseId(payMer.getUserBaseId());
            createRewardYxyDTO.setToUserBaseId(terminal.getAllyUserBaseId());
            createRewardYxyDTO.setActiveTime(LocalDateTime.now());
            createRewardYxyDTO.setRewardExpiredTime(bindResult.getData().getRefundOutTime());
            createRewardYxyDTO.setPlatNo(terminal.getPlatNo());
            createRewardYxyDTO.setTerminalPolicyName(terminal.getTerminalPolicyName());
            createRewardYxyDTO.setChannelId(terminal.getChannelId());
            createRewardYxyDTO.setTerminalRateId(terminal.getTerminalRateId());
            Result<Void> createRewardYxy = merchantYxyRewardApiService.createRewardYxy(createRewardYxyDTO);
            if (!createRewardYxy.isSuccess()) {
                KLog.warn("【机具激活通知】初始化银小云返现阶段失败:{},入参:{}", createRewardYxy.getDesc(), createRewardYxyDTO.toJSON());
            }

        }

        //发送激活机具私信
        sendActiveLetter(payMer);

    }

    /**
     * 机具强制反激活
     */
    private void posReverseOpen(Merchant payMer) {
        LocalDateTime now = LocalDateTime.now();
        if (PlatNoEnums.YXY.isEquals(payMer.getPlatNo())){
            RpcYxyTerminalReverseDTO reverseDTO = new RpcYxyTerminalReverseDTO();
            reverseDTO.setUserBaseId(payMer.getUserBaseId());
            reverseDTO.setChannelId(payMer.getChannelId());
            Result<Void> reverseSult = rpcYxyTerminalService.reverse(reverseDTO);
            if (!reverseSult.isSuccess()) {
                KLog.warn("【机具强制反激活】未成功:{}, merchant:{}", reverseSult.getDesc(), payMer.toJSON());
            }

            if (payTransactionOrderService.countByUserEpos(payMer.getUserBaseId()) < 1) {
                Merchant21 mer = merchant21Mapper.selectByPrimaryKey(payMer.getMerchantId());
                if (mer != null) {
                    mer.setTerminalActiveTime(null);
                    mer.setRemarks(payMer.getRemarks() + ";" + now + "强制反激活");
                    mer.setUpdateTime(now);
                    int upMerCc = merchant21Mapper.updateByPrimaryKey(mer);
                    BizAssertUtils.assertOne(upMerCc, "更新商户信息失败");
                }
            }
        } else {
            RpcTerminalReverseDTO reverseDTO = new RpcTerminalReverseDTO();
            reverseDTO.setUserBaseId(payMer.getUserBaseId());
            Result<Void> reverseSult = terminalService.reverse(reverseDTO);
            if (!reverseSult.isSuccess()) {
                KLog.warn("【机具强制反激活】未成功:{}, merchant:{}", reverseSult.getDesc(), payMer.toJSON());
            }

            if (payTransactionOrderService.countByUserEpos(payMer.getUserBaseId()) < 1) {
                Merchant20 mer = merchant20Mapper.selectByPrimaryKey(payMer.getMerchantId());
                if (mer != null) {
                    mer.setTerminalActiveTime(null);
                    mer.setRemarks(payMer.getRemarks() + ";" + now + "强制反激活");
                    mer.setUpdateTime(now);
                    int upMerCc = merchant20Mapper.updateByPrimaryKey(mer);
                    BizAssertUtils.assertOne(upMerCc, "更新商户信息失败");
                }
            }
        }
    }

    /**
     * 发送激活机具私信
     */
    private void sendActiveLetter(Merchant mer) {
        SendLetterDTO letterMer = new SendLetterDTO();
        letterMer.setLetterCodeEnum(LetterCodeEnum.NOTICE_EPOS_MERCHANT_ACT);
        letterMer.setPlatNo(mer.getPlatNo());
        letterMer.setUserBaseId(mer.getUserBaseId());
        letterMer.setAppId(PlatNoEnums.KLKS.isEquals(mer.getPlatNo()) ? AppId.KLKS_PRO : AppId.YXY_MER);
        mcenterRpcLetterService.send(letterMer);

        UserMerchantRecommend20Example recommend20Example = new UserMerchantRecommend20Example();
        recommend20Example.createCriteria()
                .andUserBaseIdEqualTo(mer.getUserBaseId());
        List<UserMerchantRecommend20> recommend20s = userMerchantRecommend20Mapper.selectByExample(recommend20Example);
        if (CollectionUtils.isEmpty(recommend20s)) {
            return;
        }
        UserMerchantRecommend20 recommend = recommend20s.get(0);
        Map<String, String> map = new HashMap<>();
        map.put("name", mer.getRealName());
        SendLetterDTO letterAlly = new SendLetterDTO();
        letterAlly.setLetterCodeEnum(LetterCodeEnum.NOTICE_EPOS_ALLY_ACT);
        letterAlly.setPlatNo(mer.getPlatNo());
        letterAlly.setUserBaseId(recommend.getBelongMerchantUserBaseId());
        letterAlly.setAppId(PlatNoEnums.KLKS.isEquals(mer.getPlatNo()) ? AppId.KLKS_PRO : AppId.YXY_MER);
        letterAlly.setMap(map);
        mcenterRpcLetterService.send(letterAlly);
    }

    /**
     * 发送激活机具推送
     */
    @Override
    public void merOpenJpush(String userBaseId, Short platNo) {
        SendPushDTO pushDTO = new SendPushDTO();
        pushDTO.setAppId(PlatNoEnums.KLKS.isEquals(platNo) ? AppId.KLKS_PRO : AppId.YXY_MER);
        pushDTO.setContent("恭喜您已激活机具");
        pushDTO.setUserBaseId(userBaseId);
        Map<PushExtra.PushExtCode, String> extra = new HashMap<>();
        extra.put(PushExtra.PushExtCode.ID, userBaseId);
        extra.put(PushExtra.PushExtCode.TYPE, PushExtra.PushTypeName.epos_open.getName());
        pushDTO.setPushExtra(extra);
        jpushApiService.sendPush(pushDTO);
    }
}
